/**
 *  Copyright 2002-2009 the original author or authors.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package foo.bar.blog.core.services;

import foo.bar.blog.core.domain.*;
import foo.bar.blog.core.services.exception.*;
import foo.bar.blog.utils.CollectionUtils;
import foo.bar.blog.utils.Transformer;
import foo.bar.blog.web.action.Calendar;
import foo.bar.blog.web.action.ExtendedPaginatedList;
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.JpaTemplate;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import java.io.File;
import java.io.FileFilter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * A service that deals with {@link foo.bar.blog.core.domain.Blog} related user cases.
 *
 * @author tmjee
 * @version $Date: 2009-07-05 10:12:59 +0000 (Sun, 05 Jul 2009) $ $Id$
 */
public class BlogService extends AbstractJpaAwareService {
    BlogService(){}
    public BlogService(JpaTemplate template) {
        super(template);
    }


    /**
     * Delete the {@link foo.bar.blog.core.domain.Entry}.
     * @param entry
     */
    public void deleteBlogEntry(final Entry entry) {
        getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                entityManager.remove(entry);
                return null;
            }
        });
    }

    /**
     * Delete the blog entry's {@link foo.bar.blog.core.domain.Comment}
     * @param comment
     */
    public void deleteBlogEntryComment(final Comment comment) {
        getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                entityManager.remove(comment);    
                return null;
            }
        });
    }

    /**
     * Returns a {@link foo.bar.blog.web.action.ExtendedPaginatedList} of {@link foo.bar.blog.core.domain.Blog} whose onwer is
     * the given <code>owner</code>.
     * 
     * @param owner
     * @param paginatedList
     * @return
     */
    public ExtendedPaginatedList getOwnershipBlogs(final User owner, final ExtendedPaginatedList paginatedList) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q1 = entityManager.createNamedQuery("blog_findOwnershipBlog");
                q1.setParameter("owner", owner);

                Query q2 = entityManager.createNamedQuery("blog_countOnwerhsipBlog");
                q2.setParameter("owner", owner);

                return populatePagniatedList(paginatedList,
                        prepareQueryWithPaginatedListInfo(paginatedList, q1).getResultList(),
                        (Long)prepareQueryWithPaginatedListInfo(paginatedList, q2).getSingleResult());

            }
        });
    }

    /**
     * Returns a {@link foo.bar.blog.web.action.ExtendedPaginatedList} of {@link foo.bar.blog.core.domain.Blog} whose member
     * is the given <code>member</code>.
     *
     * @param member
     * @param paginatedList
     * @return
     */
    public ExtendedPaginatedList getMembershipBlogs(final User member, final ExtendedPaginatedList paginatedList) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q1 = entityManager.createNamedQuery("blog_findMembershipBlog");
                q1.setParameter("memId", member.getId());

                Query q2 = entityManager.createNamedQuery("blog_countMembershipBlog");
                q2.setParameter("memId", member.getId());

                return populatePagniatedList(paginatedList,
                        prepareQueryWithPaginatedListInfo(paginatedList, q1).getResultList(),
                        (Long)prepareQueryWithPaginatedListInfo(paginatedList, q2).getSingleResult());
            }
        });
    }


    /**
     * Return the {@link foo.bar.blog.core.domain.Blog} having the given <code>id</code>.
     * @param id
     * @return
     */
    public Blog getBlog(final long id) {
        return (Blog) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query query = entityManager.createNamedQuery("blog_findBlogById");
                query.setParameter("id", id);
                return (Blog) getFirstResult(query);
                //return (Blog) query.getSingleResult();
            }
        });
    }


    /**
     * Delete the given <code>blog</code>.
     * @param blog
     */
    public void deleteBlog(final Blog blog) {
        getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                entityManager.remove(blog);
                return null;
            }
        });
    }

    /**
     * save the given <code>blog</code>
     * @param blog
     * @throws BlogAlreadyExistsException if the blog name already exists.
     */
    public Blog saveBlog(final Blog blog) throws BlogAlreadyExistsException {
        return (Blog) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q = entityManager.createNamedQuery("blog_countBlogByName");
                q.setParameter("name", blog.getName());
                if (((Long)q.getSingleResult()) > 0) {
                    throw new BlogAlreadyExistsException("Blog with name ["+blog.getName()+"] already exists");
                }
                Identifiable _identifiable = saveOrUpdate(entityManager, blog);
                entityManager.flush();
                return _identifiable;
            }
        });
    }

    /**
     * Update the given <code>blog</code>, if none exists yet create one.
     * @param blog
     */
    public Blog updateBlog(final Blog blog) {
        return (Blog) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Identifiable _identifiable = saveOrUpdate(entityManager, blog);
                entityManager.flush();
                return _identifiable;
            }
        });    
    }

    /**
     * Get the entries of this blog. 
     * @param blog
     * @param paginatedList
     * @return
     */
    public ExtendedPaginatedList getEntries(final Blog blog, final ExtendedPaginatedList paginatedList) {
            return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback() {
                public Object doInJpa(EntityManager entityManager) throws PersistenceException {

                    Query q1 = entityManager.createNamedQuery("blog_findBlogEntries");
                    q1.setParameter("blog", blog);

                    Query q2= entityManager.createNamedQuery("blog_countBlogEntries");
                    q2.setParameter("blog", blog);

                    return populatePagniatedList(paginatedList,
                            prepareQueryWithPaginatedListInfo(paginatedList, q1).getResultList(),
                            (Long)prepareQueryWithPaginatedListInfo(paginatedList, q2).getSingleResult());
                }
            });
        }



    public ExtendedPaginatedList getPublishedEntries(final Blog blog, final ExtendedPaginatedList paginatedList) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {

                Query q1 = entityManager.createNamedQuery("blog_findBlogEntriesByState");
                q1.setParameter("blog", blog);
                q1.setParameter("state", EntryState.PUBLISHED);

                Query q2= entityManager.createNamedQuery("blog_countBlogEntriesByState");
                q2.setParameter("blog", blog);
                q2.setParameter("state", EntryState.PUBLISHED);

                return populatePagniatedList(paginatedList,
                        prepareQueryWithPaginatedListInfo(paginatedList, q1).getResultList(),
                        (Long)prepareQueryWithPaginatedListInfo(paginatedList, q2).getSingleResult());
            }
        });
    }


    public Entry getBlogEntry(final Long id) {
        return (Entry) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query query = entityManager.createNamedQuery("entry_findEntryById");
                query.setParameter("id", id);
                //return query.getSingleResult();
                return getFirstResult(query);
            }
        });
    }

    public Entry saveBlogEntry(final Entry entry) throws BlogEntryAlreadyExistsException {
        return (Entry) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q = entityManager.createNamedQuery("entry_countEntryByNameAndBlog");
                q.setParameter("name", entry.getName());
                q.setParameter("blog", entry.getBlog());
                if (((Long)q.getSingleResult()) > 0) {
                    throw new BlogEntryAlreadyExistsException("Blog entry with the name ["+entry.getName()+"] already exists");
                }

                entry.setState(EntryState.DRAFT);
                Identifiable _identifiable = saveOrUpdate(entityManager, entry);
                entityManager.flush();
                return _identifiable;
            }
        });
    }

    public Entry publishBlogEntry(final Entry entry) {
        return (Entry) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws BlogEntryAlreadyExistsException {

                Query q = entityManager.createNamedQuery("entry_countEntryByNameAndBlog");
                q.setParameter("name", entry.getName());
                q.setParameter("blog", entry.getBlog());
                long s = (Long)q.getSingleResult();
                if ((s > 0) && (entry.getId() <= 0)) { // an Entry with this name already exists, and we want to insert a new entry? No cannot be done.
                    throw new BlogEntryAlreadyExistsException("Blog entry with name ["+entry.getName()+"] already exists");
                }

                entry.setState(EntryState.PUBLISHED);
                entry.setPublishDate(new Date());
                Identifiable identifiable = saveOrUpdate(entityManager, entry);
                entityManager.flush();
                return identifiable;
            }
        });
    }

    public Comment getComment(final long id) {
        return (Comment) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query query = entityManager.createNamedQuery("comment_findCommentById");
                query.setParameter("id", id);
                //return query.getSingleResult();
                return getFirstResult(query);
            }
        });
    }


    public ExtendedPaginatedList getLinks(final Blog blog, final ExtendedPaginatedList paginatedList) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q1 = entityManager.createNamedQuery("link_findAllLinksByBlog");
                q1.setParameter("blog", blog);
                prepareQueryWithPaginatedListInfo(paginatedList, q1);

                Query q2 = entityManager.createNamedQuery("link_countAllLinksByBlog");
                q2.setParameter("blog", blog);
                long size = (Long) q2.getSingleResult();
                
                return populatePagniatedList(paginatedList, q1.getResultList(), size);
            }
        });
    }

    public List<Link> getAllLinks(final Blog blog) {
        return (List<Link>) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query query = entityManager.createNamedQuery("link_findAllLinksByBlog");
                query.setParameter("blog", blog);
                return query.getResultList();
            }
        });
    }


    public ExtendedPaginatedList getResources(final Entry entry, final ExtendedPaginatedList paginatedList) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q1 = entityManager.createNamedQuery("resource_findAllResourcesByEntry");
                q1.setParameter("entry", entry);
                prepareQueryWithPaginatedListInfo(paginatedList, q1);

                Query q2 = entityManager.createNamedQuery("resource_countAllResourcesByEntry");
                q2.setParameter("entry", entry);
                long size = (Long) q2.getSingleResult();

                return populatePagniatedList(paginatedList, q1.getResultList(), size);
            }
        });
    }

    public ExtendedPaginatedList getTags(final Blog blog, final ExtendedPaginatedList paginatedList) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q1 = entityManager.createNamedQuery("tag_findAllTagsByBlog");
                q1.setParameter("blog", blog);
                prepareQueryWithPaginatedListInfo(paginatedList, q1);

                Query q2 = entityManager.createNamedQuery("tag_countAllTagsByBlog");
                q2.setParameter("blog", blog);
                long size = (Long) q2.getSingleResult();

                return populatePagniatedList(paginatedList, q1.getResultList(), size);
            }
        });
    }

    public List<Tag> getAllTags(final Blog blog) {
        return (List<Tag>) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query query = entityManager.createNamedQuery("tag_findAllTagsByBlog");
                query.setParameter("blog", blog);
                return query.getResultList();
            }
        });
    }


    public Link getLink(final long id) {
        return (Link) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query query = entityManager.createNamedQuery("link_findLinkById") ;
                query.setParameter("id", id);
                //return query.getSingleResult();
                return getFirstResult(query);
            }
        });
    }



    public Tag getTag(final long id) {
        return (Tag) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query query = entityManager.createNamedQuery("tag_findTagById");
                query.setParameter("id", id);
                //return query.getSingleResult();
                return getFirstResult(query);
            }
        });
    }

    public Resource getResource(final long id) {
        return (Resource) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query query = entityManager.createNamedQuery("resource_findResourceById");
                query.setParameter("id", id);
                //return query.getSingleResult();
                return getFirstResult(query);
            }
        });
    }

    public Resource getResourceByNameAndEntryId(final String resourceName, final long entryId) {
        return (Resource) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query query = entityManager.createNamedQuery("resource_findResourceByNameAndEntryId");
                query.setParameter("resourceName", resourceName);
                query.setParameter("entryId", entryId);
                return getFirstResult(query);
            }
        });
    }


    public Link saveLink(final Link link) throws LinkAlreadyExistsException {
        return (Link) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query query = entityManager.createNamedQuery("link_countLinkByNameAndBlog");
                query.setParameter("name", link.getName());
                query.setParameter("blog", link.getBlog());
                if (((Long)query.getSingleResult()) > 0) {
                    throw new LinkAlreadyExistsException("Link with name ["+link.getName()+"] already exists");
                }

                Identifiable identifiable =  saveOrUpdate(entityManager, link);
                entityManager.flush();
                return identifiable;
            }
        });
    }

    public Link updateLink(final Link link) {
        return (Link) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Identifiable identifiable =  saveOrUpdate(entityManager, link);
                entityManager.flush();
                return identifiable;
            }
        });    
    }

    public Tag saveTag(final Tag tag) throws TagAlreadyExistsException {
        return (Tag) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q = entityManager.createNamedQuery("tag_countTagByNameAndBlog");
                q.setParameter("name", tag.getName());
                q.setParameter("blog", tag.getBlog());
                if (((Long)q.getSingleResult()) > 0) {
                    throw new TagAlreadyExistsException("Tag with name ["+tag.getName()+"] already exists");
                }
                Identifiable identifiable = saveOrUpdate(entityManager, tag);
                entityManager.flush();
                return identifiable;
            }
        });
    }

    public Tag updateTag(final Tag tag) {
        return (Tag) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Identifiable identifiable = saveOrUpdate(entityManager, tag);
                entityManager.flush();
                return identifiable;
            }
        });    
    }

    public Resource saveResource(final Resource resource) throws ResourceAlreadyExistsException {
        return (Resource) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q = entityManager.createNamedQuery("resource_countResourceByNameAndEntry");
                q.setParameter("name", resource.getName());
                q.setParameter("entry", resource.getEntry());
                if (((Long)q.getSingleResult()) > 0) {
                    throw new ResourceAlreadyExistsException("Resource with name ["+resource.getName()+"] already exists");
                }

                Identifiable identifiable = saveOrUpdate(entityManager, resource);
                entityManager.flush();
                return identifiable;
            }
        });
    }

    public Resource updateResource(final Resource resource) {
        return (Resource) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Identifiable identifiable = saveOrUpdate(entityManager, resource);
                entityManager.flush();
                return identifiable;
            }
        });    
    }


    public void deleteLink(final Link link) {
        getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                entityManager.remove(link);
                return null;
            }
        });
    }


    public void deleteTag(final Tag tag) {
        getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q = entityManager.createNamedQuery("tag_findEntryWithTag");
                q.setParameter("tag", tag);
                List<Entry> entriesWithThisTag = q.getResultList();
                for (Entry entryWithThisTag: entriesWithThisTag) {
                    entryWithThisTag.setTag(null);    
                }
                entityManager.remove(tag);
                return null;
            }
        });
    }

    public void deleteResource(final Resource resource) {
        getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                entityManager.remove(resource);
                return null;
            }
        });
    }

    public ExtendedPaginatedList getPublishedTaggedEntries(final Blog blog, final Tag selectedTag, final ExtendedPaginatedList paginatedList) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q1 = entityManager.createNamedQuery("blog_findBlogEntriesByTagAndState");
                prepareQueryWithPaginatedListInfo(paginatedList, q1);
                q1.setParameter("blog", blog);
                q1.setParameter("tag", selectedTag);
                q1.setParameter("state", EntryState.PUBLISHED);


                Query q2 = entityManager.createNamedQuery("blog_countBlogEntriesByTagAndState");
                q2.setParameter("blog", blog);
                q2.setParameter("tag", selectedTag);
                q2.setParameter("state", EntryState.PUBLISHED);
                long size = (Long) q2.getSingleResult();

                return populatePagniatedList(paginatedList, q1.getResultList(), size);
            }
        });
    }


    public List<String> getAllBlogThemeNames() throws URISyntaxException {
        // TODO: io access everytime? can we cache this?
        URI blogThemeUri= getClass().getResource("/blogTheme").toURI();
        File blogThemeDir = new File(blogThemeUri);

        File[] blogThemeFiles = blogThemeDir.listFiles(new FileFilter(){
            public boolean accept(File pathname) {
                if (pathname.getName().toLowerCase().endsWith(".properties")) {
                    return true;
                }
                return false;
            }
        });

        List<String> blogThemeNames = new ArrayList<String>();
        for (File blogThemeFile : blogThemeFiles) {
            String filename = blogThemeFile.getName();
            int index = filename.indexOf(".properties");
            if (index > 0) {
                blogThemeNames.add(blogThemeFile.getName().substring(0, index));
            }
        }

        return blogThemeNames;
    }

    public List<Entry> getLatestPublishedEntries() {
        return (List<Entry>) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q1 = entityManager.createNamedQuery("entry_findLatestPublishedEntries");
                q1.setParameter("state", EntryState.PUBLISHED);
                q1.setFirstResult(0);
                q1.setMaxResults(30);
                return q1.getResultList();
            }
        });
    }

    public List<Blog> getLatestBlogs() {
        return (List<Blog>) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q1 = entityManager.createNamedQuery("blog_findLatestBlogs");
                q1.setFirstResult(0);
                q1.setMaxResults(30);
                return q1.getResultList();
            }
        });
    }

    public ExtendedPaginatedList getWeblogDirectories(final ExtendedPaginatedList paginatedList,
                                                      final String weblogDirectoryCharacter) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q1 = entityManager.createNamedQuery("blog_findBlogByLikelyName");
                q1.setParameter("blogName", weblogDirectoryCharacter.toLowerCase()+"%");
                prepareQueryWithPaginatedListInfo(paginatedList, q1);

                Query q2 = entityManager.createNamedQuery("blog_countFindBlogByLikelyName");
                q2.setParameter("blogName", weblogDirectoryCharacter.toLowerCase()+"%");
                Long total = (Long) q2.getSingleResult();
                return populatePagniatedList(paginatedList, q1.getResultList(), total);
            }
        });
    }

    public void addMembersToBlog(final List<User> toBeAddedMembers, final Blog blog) {
        getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                for (User toBeAddedMember : toBeAddedMembers) {
                    blog.addMember(toBeAddedMember);
                }
                saveOrUpdate(entityManager, blog);
                return null;
            }
        });
    }

    public ExtendedPaginatedList getBlogNonMembers(final ExtendedPaginatedList paginatedList, final Blog blog, final String search) {
        final Set<Long> blogMemberIds = CollectionUtils.collect(blog.getMembers(), new Transformer<User, Long>(){
            public Long transform(User user) {
                return user.getId();
            }
        });

        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {

                if (search == null || (search.trim().length()<=0)) {
                    Query q1 = entityManager.createNamedQuery("blog_nonMembers");
                    prepareQueryWithPaginatedListInfo(paginatedList, q1);
                    q1.setParameter("memIds", blogMemberIds);
                    q1.setParameter("blog", blog);

                    Query q2 = entityManager.createNamedQuery("blog_countNonMembers");
                    q2.setParameter("memIds", blogMemberIds);
                    q2.setParameter("blog", blog);
                    long size = (Long) q2.getSingleResult();

                    populatePagniatedList(paginatedList, q1.getResultList(), size);
                    return paginatedList;
                }
                else {
                    String effectiveSearch = "%"+search.trim().toLowerCase()+"%";
                    Query q1 = entityManager.createNamedQuery("blog_searchNonMembers");
                    prepareQueryWithPaginatedListInfo(paginatedList, q1);
                    q1.setParameter("blog", blog);
                    q1.setParameter("memIds", blogMemberIds);
                    q1.setParameter("search", effectiveSearch);

                    Query q2 = entityManager.createNamedQuery("blog_countSearchNonMembers");
                    q2.setParameter("blog", blog);
                    q2.setParameter("memIds", blogMemberIds);
                    q2.setParameter("search", effectiveSearch);
                    long size = (Long) q2.getSingleResult();

                    populatePagniatedList(paginatedList, q1.getResultList(), size);
                    return paginatedList;
                }
            }
        });
    }

    public ExtendedPaginatedList getBlogMembers(final ExtendedPaginatedList paginatedList, final Blog blog) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {

                Query q1 = entityManager.createNamedQuery("blog_members");
                prepareQueryWithPaginatedListInfo(paginatedList, q1);
                q1.setParameter("blog", blog);

                Query q2 = entityManager.createNamedQuery("blog_countMembers");
                q2.setParameter("blog", blog);
                long size = (Long)q2.getSingleResult();

                return populatePagniatedList(paginatedList, q1.getResultList(), size);
            }
        });
    }

    public void removeMembersFromBlog(final List<User> toBeRemovedMembers, final Blog blog) {
        getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                for (User toBeRemovedMember: toBeRemovedMembers) {
                    blog.removeMember(toBeRemovedMember);
                }
                return null;
            }
        });
    }

    public ExtendedPaginatedList getCalendaredEntries(final Blog blog, final Calendar calendar, final ExtendedPaginatedList paginatedList) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q1 = entityManager.createNamedQuery("blog_getBlogEntriesPublishedBetweenDates");
                prepareQueryWithPaginatedListInfo(paginatedList, q1);
                q1.setParameter("blog", blog);
                q1.setParameter("startDate", calendar.getStartDate());
                q1.setParameter("endDate", calendar.getEndDate());

                Query q2 = entityManager.createNamedQuery("blog_countBlogEntriesPublishedBetweenDates");
                q2.setParameter("blog", blog);
                q2.setParameter("startDate", calendar.getStartDate());
                q2.setParameter("endDate", calendar.getEndDate());
                long size = (Long) q2.getSingleResult();

                return populatePagniatedList(paginatedList, q1.getResultList(), size);
            }
        });
    }

    public List<Date> getDatesWithBlogEntries(final Blog blog, final Date startDate, final Date endDate) {
        return (List<Date>) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query query = entityManager.createNamedQuery("blog_datesOfBlogEntriesWithEntries");
                query.setParameter("blog", blog);
                query.setParameter("startDate", startDate);
                query.setParameter("endDate", endDate);
                return query.getResultList();
            }
        });
    }

    public ExtendedPaginatedList searchPublishedEntries(final Blog blog, final String search, final ExtendedPaginatedList paginatedList) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                String _search = "%"+search.trim().toLowerCase()+"%";

                Query q1 = entityManager.createNamedQuery("blog_searchBlogEntriesPublished");
                q1.setParameter("blog", blog);
                q1.setParameter("search", _search);
                prepareQueryWithPaginatedListInfo(paginatedList, q1);

                Query q2 = entityManager.createNamedQuery("blog_countSearchBlogEntriesPublished");
                q2.setParameter("blog", blog);
                q2.setParameter("search", _search);
                long size = (Long) q2.getSingleResult();

                return populatePagniatedList(paginatedList, q1.getResultList(), size);
            }
        });
    }

    public Comment saveBlogEntryComment(final Comment entryComment) {
        return (Comment) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Identifiable identifiable = saveOrUpdate(entityManager, entryComment);
                entityManager.flush();
                return identifiable;
            }
        });
    }

    public ExtendedPaginatedList searchBlogs(final String searchCriteria, final ExtendedPaginatedList paginatedList) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                String _searchCriteria = searchCriteria == null ? "" : searchCriteria.toLowerCase();
                Query q2 = entityManager.createNamedQuery("blog_countSearchAllBlogEntriesPublished");
                q2.setParameter("search", searchCriteria == null ? "%" : "%"+_searchCriteria+"%");

                Query q1 = entityManager.createNamedQuery("blog_searchAllBlogEntriesPublished");
                q1.setParameter("search", searchCriteria == null ? "%" : "%"+_searchCriteria+"%");
                prepareQueryWithPaginatedListInfo(paginatedList, q1);

                return populatePagniatedList(paginatedList, q1.getResultList(), (Long)q2.getSingleResult());
            }
        });
    }

    public ExtendedPaginatedList searchDirectories(final String searchCriteria, final ExtendedPaginatedList paginatedList) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback(){
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                String _searchCriteria = searchCriteria == null ? "" : searchCriteria.toLowerCase();
                Query q1 = entityManager.createNamedQuery("blog_findBlogByLikelyName");
                q1.setParameter("blogName", searchCriteria == null ? "%" : "%"+_searchCriteria+"%");
                prepareQueryWithPaginatedListInfo(paginatedList, q1);

                Query q2 = entityManager.createNamedQuery("blog_countFindBlogByLikelyName");
                q2.setParameter("blogName", searchCriteria == null ? "%" : "%"+_searchCriteria+"%");
                Long total = (Long) q2.getSingleResult();
                return populatePagniatedList(paginatedList, q1.getResultList(), total);
            }
        });
    }

    public ExtendedPaginatedList getAllBlogs(final ExtendedPaginatedList paginatedList) {
        return (ExtendedPaginatedList) getJpaTemplate().execute(new JpaCallback() {
            public Object doInJpa(EntityManager entityManager) throws PersistenceException {
                Query q1 = entityManager.createNamedQuery("blog_findAllBlogs");
                prepareQueryWithPaginatedListInfo(paginatedList, q1);

                Query q2 = entityManager.createNamedQuery("blog_countAllBlogs");
                Long total = (Long) q2.getSingleResult();

                return populatePagniatedList(paginatedList, q1.getResultList(), total);
            }
        });
    }
}
